/**
 * Copyright (c) 2011-2013, kidzhou 周磊 (zhouleib1412@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * modified by sunny 2015-12-08
 */
package uf.audit.util;

/**
 * 改写JFinal Ext的代码，主要为AuditRoute服务
 */

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.log4j.Logger;

import com.google.common.collect.Lists;
import com.jfinal.ext.kit.Reflect;
import com.jfinal.kit.PathKit;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;

import javax.servlet.ServletException;

@SuppressWarnings("rawtypes")
public class ClassSearcher {

	public static final String DEFAULT_SCAN_CLASSPATH = "classpath:*";
	private static final Logger log = Logger.getLogger(ClassSearcher.class);

	private String packageNs;
	private ClassPathScanningCandidateComponentProvider provider;
	private final ClassLoader classLoader = ClassSearcher.class.getClassLoader();
	private List<Class> classes;
	private List<Class> annotations;

	public ClassSearcher() {
		packageNs = DEFAULT_SCAN_CLASSPATH;
		provider = new ClassPathScanningCandidateComponentProvider(true);
		provider.setResourceLoader(new PathMatchingResourcePatternResolver(classLoader));
		classes = new ArrayList<Class>();
		annotations = new ArrayList<Class>();
	}

	public void setScanPaths(String packageNs) {
		this.packageNs = packageNs;
	}

	public void addType(Class type) {
		if (!classes.contains(type)) {
			classes.add(type);
			provider.addIncludeFilter(new AssignableTypeFilter(type));
		}
	}

	@SuppressWarnings("unchecked")
	public void addAnotation(Class type) {
		if (!classes.contains(type)) {
			annotations.add(type);
			provider.addIncludeFilter(new AnnotationTypeFilter(type));
		}
	}

	public void scanClasses(IScanInvoke invoke) {
		String[] packageNames = packageNs.split(";");
		for (String packageN : packageNames) {
			Set<BeanDefinition> beans = provider.findCandidateComponents(packageN);
			Iterator<BeanDefinition> bit = beans.iterator();
			while (bit.hasNext()) {
				BeanDefinition bi = bit.next();
				Class<?> clazz;
				try {
					clazz = Class.forName(bi.getBeanClassName(), true, classLoader);
					if (log.isDebugEnabled())
						log.debug(clazz.getName() + " is loaded");
					if (invoke != null) {
						invoke.invoke(this, clazz);
					}
				} catch (ClassNotFoundException e) {
					log.error(e.getMessage(), e);
				} catch (ServletException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
